package org.piggy.core.request;

import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.cookie.Cookie;
import io.netty.handler.codec.http.cookie.ServerCookieDecoder;
import org.apache.commons.lang3.StringUtils;
import org.asynchttpclient.Request;
import org.asynchttpclient.RequestBuilder;
import org.piggy.common.constants.BasicConst;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class GatewayRequest {

    private final long beginTime;

    private final Charset charset;

    private final String clientIp;

    private final String host;

    private final String path;

    private final String uri;

    private final HttpMethod method;

    private final String contentType;

    private final HttpHeaders headers;

    private final FullHttpRequest fullHttpRequest;

    private String body;

    private Map<String, Cookie> cookieMap;

    private String modifyScheme;

    private String modifySchemeWs;

    private String modifyHost;

    private String ip;

    private int port;

    private String userId;

    private final String modifyPath;

    private final QueryStringDecoder queryStringDecoder;

    private final RequestBuilder requestBuilder;

    public GatewayRequest(Charset charset, String clientIp, String host,
                          String uri, HttpMethod method, String contentType,
                          HttpHeaders headers, FullHttpRequest fullHttpRequest) {
        this.charset = charset;
        this.clientIp = clientIp;
        this.host = host;
        this.uri = uri;
        this.method = method;
        this.contentType = contentType;
        this.headers = headers;
        this.fullHttpRequest = fullHttpRequest;

        this.beginTime = System.currentTimeMillis();
        this.modifyScheme = BasicConst.HTTP_PREFIX_SEPARATOR;
        this.modifySchemeWs = BasicConst.WS_PREFIX_SEPARATOR;
        this.body = this.fullHttpRequest.content().toString(this.charset);

        this.queryStringDecoder = new QueryStringDecoder(this.uri, this.charset);
        this.path = this.queryStringDecoder.path();
        this.modifyPath = this.queryStringDecoder.path();

        this.requestBuilder = new RequestBuilder();
        this.requestBuilder.setMethod(this.method.name());
        this.requestBuilder.setHeaders(this.headers);
        this.requestBuilder.setQueryParams(queryStringDecoder.parameters());
        ByteBuf contentBuffer = fullHttpRequest.content();
        if(contentBuffer != null){
            this.requestBuilder.setBody(contentBuffer.nioBuffer());
        }
    }

    public void setModifySchemeWs(String modifySchemeWs) {
        this.modifySchemeWs = modifySchemeWs;
    }

    public void setModifyScheme(String modifyScheme) {
        this.modifyScheme = modifyScheme;
    }

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public long getBeginTime() {
        return beginTime;
    }

    public Charset getCharset() {
        return charset;
    }

    public String getClientIp() {
        return clientIp;
    }

    public String getHost() {
        return host;
    }

    public String getPath() {
        return path;
    }

    public String getUri() {
        return uri;
    }

    public HttpMethod getMethod() {
        return method;
    }

    public String getContentType() {
        return contentType;
    }

    public HttpHeaders getHeaders() {
        return headers;
    }

    public QueryStringDecoder getQueryStringDecoder() {
        return queryStringDecoder;
    }

    public FullHttpRequest getFullHttpRequest() {
        return fullHttpRequest;
    }

    public Map<String, Cookie> getCookieMap() {
        return cookieMap;
    }

    public String getModifyScheme() {
        return modifyScheme;
    }

    public String getModifyHost() {
        return modifyHost;
    }

    public String getModifyPath() {
        return modifyPath;
    }

    public RequestBuilder getRequestBuilder() {
        return requestBuilder;
    }

    public String getBody() {
        return body;
    }

    public String getBodySecond(){
        if(StringUtils.isEmpty(body)){
            body = fullHttpRequest.content().toString(charset);
        }
        return body;
    }

    public Cookie getCookie(String name){
        if(cookieMap == null){
            cookieMap = new HashMap<>();
            String cookieText = this.headers.get(HttpHeaderNames.COOKIE);
            Set<Cookie> cookies = ServerCookieDecoder.STRICT.decode(cookieText);
            for(Cookie cookie: cookies){
                cookieMap.put(cookie.name(), cookie);
            }
        }
        return cookieMap.get(name);
    }

    public void setModifyHost(String modifyHost) {
        this.modifyHost = modifyHost;
    }

    public  boolean isFormPost(){
        return HttpMethod.POST.equals(method) &&
                (contentType.startsWith(HttpHeaderValues.FORM_DATA.toString()) ||
                        contentType.startsWith(HttpHeaderValues.APPLICATION_X_WWW_FORM_URLENCODED.toString()));
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public boolean isJsonPost(){
        return HttpMethod.POST.equals(method) && contentType.startsWith(HttpHeaderValues.APPLICATION_JSON.toString());
    }

    public Request build() {
        requestBuilder.setUrl(getHttpUrl());
        return requestBuilder.build();
    }

    public String getHttpUrl() {
        return modifyScheme + modifyHost + modifyPath;
    }

    public String getWsUrl() {
        return modifySchemeWs + modifyHost + modifyPath;
    }

}
